--local StateList = require('src/list_states')

local Class = require('src/Class')
--local Entity = require('src/Entities/Entity')
local Log = require('src/Log')

local Core = Class:derive('Core')

function character(v)
    if v.name then
        Log:debug('Found character: '..v.name)
    else
        Log:error('Missing name in character!')
        error('Missing name in character: ', 2)
    end
    if base.characters[v.name] then
        Log:warning('Character already loaded: '..v.name)
    end
    base.characters[v.name] = v
    return v
end

function location(v) -- location constructor
    if v.name then
        Log:debug('Found location: '..v.name)
    else
        Log:error('Missing name in location!')
        error('Missing name in location: ', 2)
    end
--    if v.way == nil then
--        v.way = { }
--    end
--    v.way = list(v.way)
--    v = obj(v)
    if base.locations[v.name] then
        Log:warning('Location already loaded: '..v.name)
    end
    base.locations[v.name] = v
    return v
end


function screen(v) -- screen constructor
    if v.name then
        Log:debug('Found screen: '..v.name)
    else
        Log:error('Missing name in location!')
        error('Missing name in screen: ', 2)
    end
    v.screen = true
    if base.screens[v.name] then
        Log:warning('Location already loaded: '..v.name)
    end
    base.screens[v.name] = v
    return v
end


--function objects(v) -- objects constructor
--print('objects')
--print_r(v)
----    base.objects[]
--    return v
--end

function Core:new()
--    self.states = {}
--    self.stack = {}

--    for _, state in pairs(StateList) do
--        local path = statePath .. '/' .. state
--        local M = require(path)
--        self.states[state] = M
--    end
end

function Core.here()
    return game.characters[game.player].where
end

--function Core:start(filename)
--    Log:info('Core: Starting: '..filename)
--    dofile(filename)
--end

function Core:init()
    Log:info('Core: Initializing main...')
--    Core:start('scripts/main.lua')
    local filename = 'scripts/main.lua'
    Log:info('Core: Starting script: '..filename)
    dofile(filename)
    ENGINE.CORE:initPlayer(base.player)
    game.player = base.player
end

function Core:initIntro()
    Log:info('Core: Initializing intro...')
    ENGINE.CORE:walk('intro_001')
end

function Core:initWinter()
    Log:info('Core: Initializing winter...')
    ENGINE.CORE:walk('intro_001')
--    ENGINE.CORE:walk('test_01')
    ENGINE.CORE:walk('MainMenu')
end

function Core:initPlayer(name)
    Log:debug('Core: Initializing player: '..name)
    local c = {}
    local b = base.characters[name]
    c.name = b.name
    c.where = b.where
    c.tilex = b.tilex
    c.tiley = b.tiley
    c.tileset = b.tileset
    game.characters[name] = c
end

function Core.me()
    return game.characters[game.player]
end

function Core.getReference(name)
    local ref = nil
    if base.locations[name] then
        ref = base.locations[name]
        return ref, 'location'
    end
    if base.screens[name] then
        ref = base.screens[name]
        return ref, 'screen'
    end
    if base.dialogs[name] then
        ref = base.dialogs[name]
        return ref, 'dialog'
    end
    return nil, nil
end

function Core.GetType(name)
    local t = nil
    if base.locations[name] then
        t = 'location'
    end
    if base.screens[name] then
        t = 'screen'
    end
    if base.dialogs[name] then
        t = 'dialog'
    end
-- TODO remove
--    if not t then
--        for i = 1, #StateList do
--            if local StateList = require('src/list_states')
--        end
--    end
    return t
end

function Core.functionEnter(name)
    local result = false
    local ref, refType = Core.getReference(name)
    if ref then
        if ref.enter then
            result = ref.enter()
            if result == nil then
                result = true
            end
        end
    end
    return result
end

function Core.functionExit(name)
    local result = false
    local ref, refType = Core.getReference(name)
    if ref.exit then
        result = ref.exit()
        if result == nil then
            result = true
        end
    end
    return result
end

function Core:walk(to)
    local was = Core.me().where

    -- check access
    local granted = true

    if Core.functionExit(was) then
        if Core.functionEnter(to) then
            granted = true
        end
    end
    if granted then
        n = Core.GetType(to)
        if n == 'screen' then
            n = 'ScreenState'
        end
        if n == 'location' then
            n = 'LocationState'
        end
        if not n then
            n = to..'State'
        end
--print(n, to)
--os.exit(0)
--        ENGINE.SM:InitState(n, to)
--        ENGINE.SM:Switch(to, nil)
--        Core.move(Core.me(), to)
    end
end

function Core.move(obj, loc)
    obj.where = loc
end

function Core:CreateEntities()
    local here = Core.here()
    game.entities = {}
    for k, v in pairs(game.characters) do
        if v.where == here then
            Log:debug('Core: Creating entity: '..k)
            game.entities[k] = Core:CreateEntity(k, v)
        end
    end
end

function Core:CreateEntity(name, info)
    local e = {}
    e = info
    if not e.tilex then
        e.tilex = 1
    end
    if not e.tiley then
        e.tiley = 1
    end
    return e
end

-- function Core:LoadTilesForEntity(e)
-- print_r(e)
--     local tiles = {}
--     tiles = TiledLoader:ParseTileset(e.tileset)
-- print_r(tiles)
-- os.exit(0)
-- end

function Core:GetEntityInTile(i, j)
    local r = nil
    for k, v in pairs(game.entities) do
        if v.tilex == i and v.tiley == j then
            r = k
        end
    end
    return r
end

function Core:GetTile(e)
--    local state = ENGINE.SM:getStateWithType('MapState')
    local state = ENGINE.SM:GetState('MapState')
    return state.tiles[156]
end

function Core:update(dt)
--    for k, state in pairs(self.stack) do
--        self.states[state]:update(dt)
--    end
end

function Core:draw()
--    for k, state in pairs(self.stack) do
--        self.states[state]:draw(dt)
--    end
end

return Core
